import cv2
import numpy as np
import logging
import os
import yaml
from huggingface_hub import hf_hub_download, snapshot_download

# 配置日志
logger = logging.getLogger(__name__)

class PaddleXConfigLoader:
    def __init__(self, config_path=None):
        """
        初始化：加载PaddleX配置文件
        Args:
            config_path: 配置文件路径
        """
        if config_path is None:
            config_path = os.path.join(os.path.dirname(__file__), '..', 'configs', 'seal_recognition_config.yml')
        
        self.config_path = config_path
        self.config = self.load_config()
        
    def load_config(self):
        """加载配置文件"""
        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
            logger.info(f"配置文件加载成功：{self.config_path}")
            return config
        except Exception as e:
            logger.warning(f"配置文件加载失败：{str(e)}，使用默认配置")
            return self.get_default_config()
    
    def get_default_config(self):
        """获取默认配置"""
        return {
            "PipelineParams": {
                "use_doc_orientation_classify": False,
                "use_doc_unwarping": False
            },
            "SealDetection": {
                "min_seal_size": 0.05,
                "max_seal_size": 0.5,
                "min_aspect_ratio": 0.5,
                "max_aspect_ratio": 2.0,
                "min_confidence": 0.2
            }
        }

class PaddleXModelFromHF:
    def __init__(self, local_model_root=None, use_mirror=True):
        """
        初始化：设置本地模型保存根路径
        Args:
            local_model_root: 本地模型保存路径（默认：用户目录下 PaddleX_HF_Models）
            use_mirror: 是否使用国内镜像
        """
        self.local_root = local_model_root if local_model_root else \
            os.path.expanduser("~/PaddleX_HF_Models")
        os.makedirs(self.local_root, exist_ok=True)
        logger.info(f"本地模型根路径：{self.local_root}")
        
        # 配置镜像设置
        self.use_mirror = use_mirror
        if use_mirror:
            self._setup_mirror_config()
    
    def _setup_mirror_config(self):
        """配置国内镜像"""
        try:
            # 设置Hugging Face镜像
            os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
            
            # 设置其他可能的镜像环境变量
            os.environ["HUGGINGFACE_HUB_CACHE"] = os.path.join(self.local_root, "cache")
            os.environ["TRANSFORMERS_CACHE"] = os.path.join(self.local_root, "transformers_cache")
            
        except Exception as e:
            logger.warning(f"镜像配置失败：{str(e)}")

    def download_model(self, repo_id, model_subdir=None, force_download=False):
        """
        从 Hugging Face Hub 下载 PaddleX 模型
        Args:
            repo_id: Hugging Face 仓库ID
            model_subdir: 仓库内模型子目录
            force_download: 是否强制重新下载
        Returns:
            local_model_dir: 本地模型目录路径
        """
        # 拼接本地模型保存路径
        local_model_dir = os.path.join(self.local_root, repo_id.split("/")[-1])
        if model_subdir:
            local_model_dir = os.path.join(local_model_dir, model_subdir)
        
        # 若已存在且不强制下载，直接返回
        if os.path.exists(local_model_dir) and not force_download:
            logger.info(f"模型已存在：{local_model_dir}，跳过下载")
            return local_model_dir
        
        # 尝试多种下载方式
        download_methods = [
            ("镜像下载", self._download_with_mirror),
            ("直接下载", self._download_direct),
            ("备用下载", self._download_fallback)
        ]
        
        for method_name, download_func in download_methods:
            try:
                logger.info(f"尝试{method_name}：{repo_id}/{model_subdir if model_subdir else ''}")
                result = download_func(repo_id, local_model_dir, model_subdir, force_download)
                if result:
                    logger.info(f"✅ {method_name}成功：{local_model_dir}")
                    return local_model_dir
                else:
                    logger.warning(f"❌ {method_name}失败")
            except Exception as e:
                logger.warning(f"❌ {method_name}异常：{str(e)}")
                continue
        
        logger.error(f"所有下载方式都失败了：{repo_id}")
        return None
    
    def _download_with_mirror(self, repo_id, local_model_dir, model_subdir, force_download):
        """使用镜像下载"""
        try:
            snapshot_download(
                repo_id=repo_id,
                local_dir=local_model_dir,
                local_dir_use_symlinks=False,
                force_download=force_download,
                allow_patterns=["*.pdparams", "*.pdopt", "*.pdmodel", "model.yml", "config.yml"]
            )
            return True
        except Exception as e:
            logger.warning(f"镜像下载失败：{str(e)}")
            return False
    
    def _download_direct(self, repo_id, local_model_dir, model_subdir, force_download):
        """直接下载（不使用镜像）"""
        try:
            # 临时禁用镜像
            old_endpoint = os.environ.get("HF_ENDPOINT")
            if "HF_ENDPOINT" in os.environ:
                del os.environ["HF_ENDPOINT"]
            
            snapshot_download(
                repo_id=repo_id,
                local_dir=local_model_dir,
                local_dir_use_symlinks=False,
                force_download=force_download,
                allow_patterns=["*.pdparams", "*.pdopt", "*.pdmodel", "model.yml", "config.yml"]
            )
            
            # 恢复镜像设置
            if old_endpoint:
                os.environ["HF_ENDPOINT"] = old_endpoint
            return True
        except Exception as e:
            logger.warning(f"直接下载失败：{str(e)}")
            return False
    
    def _download_fallback(self, repo_id, local_model_dir, model_subdir, force_download):
        """备用下载方案"""
        try:
            # 使用git clone作为备用方案
            import subprocess
            import shutil
            
            temp_dir = os.path.join(self.local_root, "temp_download")
            if os.path.exists(temp_dir):
                shutil.rmtree(temp_dir)
            
            # 构建下载URL
            if self.use_mirror:
                download_url = f"https://hf-mirror.com/{repo_id}"
            else:
                download_url = f"https://huggingface.co/{repo_id}"
            
            # 使用git clone
            cmd = ["git", "clone", download_url, temp_dir]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
            
            if result.returncode == 0:
                # 移动文件到目标目录
                if os.path.exists(local_model_dir):
                    shutil.rmtree(local_model_dir)
                shutil.move(temp_dir, local_model_dir)
                return True
            else:
                logger.warning(f"Git clone失败：{result.stderr}")
                return False
                
        except Exception as e:
            logger.warning(f"备用下载失败：{str(e)}")
            return False

    def load_and_verify_model(self, local_model_dir, model_type="detection"):
        """
        加载模型并验证可用性
        Args:
            local_model_dir: 本地模型目录
            model_type: 模型类型
        Returns:
            model: 加载成功的 PaddleX 模型
        """
        if not local_model_dir or not os.path.exists(local_model_dir):
            logger.warning(f"模型目录不存在：{local_model_dir}")
            return None
            
        try:
            import paddlex as pdx
            
            # 检查必要的模型文件
            required_files = ['model.pdparams', 'model.pdopt', 'config.yml', 'inference.yml']
            missing_files = []
            for file_name in required_files:
                file_path = os.path.join(local_model_dir, file_name)
                if not os.path.exists(file_path):
                    missing_files.append(file_name)
            
            if missing_files:
                logger.warning(f"模型文件缺失：{missing_files}")
                return None
            
            # 根据模型类型选择正确的模型类型
            try:
                if model_type == "detection":
                    model = pdx.create_predictor('PaddleDetection', model_dir=local_model_dir)
                elif model_type == "recognition":
                    model = pdx.create_predictor('PaddleOCR', model_dir=local_model_dir)
                else:
                    # 默认使用PaddleDetection
                    model = pdx.create_predictor('PaddleDetection', model_dir=local_model_dir)
                
                logger.info(f"模型加载成功：{local_model_dir} (类型: {model_type})")
                return model
            except Exception as model_error:
                logger.warning(f"PaddleX模型创建失败：{str(model_error)}")
                # 尝试使用更简单的方式加载模型
                try:
                    # 尝试不同的模型名称
                    model_names = ['PaddleDetection', 'PaddleOCR', 'PaddleX']
                    for model_name in model_names:
                        try:
                            model = pdx.create_predictor(model_name, model_dir=local_model_dir)
                            logger.info(f"模型加载成功（使用{model_name}）：{local_model_dir}")
                            return model
                        except Exception as name_error:
                            logger.debug(f"使用{model_name}失败：{str(name_error)}")
                            continue
                    
                    # 如果所有模型名称都失败，尝试使用默认模型名称
                    try:
                        model = pdx.create_predictor('PaddleDetection', model_dir=local_model_dir)
                        logger.info(f"模型加载成功（默认PaddleDetection）：{local_model_dir}")
                        return model
                    except Exception as default_error:
                        logger.warning(f"默认模型加载也失败：{str(default_error)}")
                        return None
                except Exception as simple_error:
                    logger.warning(f"所有模型加载方式都失败：{str(simple_error)}")
                    return None
            
        except Exception as e:
            logger.warning(f"模型加载失败：{str(e)}")
            return None

class PaddleXSealDetector:
    """基于PaddleX的印章检测和识别类"""
    
    def __init__(self, config_path=None, use_handwritten=False):
        """初始化PaddleX模型"""
        try:
            import paddlex as pdx
            logger.info("PaddleX导入成功")
            
            # 配置Mac CPU环境
            os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
            logger.info("已配置Mac CPU运行模式")
            
            # 检查PaddleX版本
            pdx_version = getattr(pdx, '__version__', 'unknown')
            logger.info(f"PaddleX版本：{pdx_version}")
            
            # 使用PaddleX印章识别管道
            logger.info("使用PaddleX印章识别管道...")
            
            # 加载配置文件
            config_loader = PaddleXConfigLoader(config_path)
            self.pdx_config = config_loader.config
            
            # 1. 印章识别管道（保留）
            self.pdx_pipeline = None
            try:
                # 创建印章识别管道
                from paddlex import create_pipeline
                self.pdx_pipeline = create_pipeline(pipeline="seal_recognition")
                logger.info("✅ PaddleX印章识别管道创建成功")
                
                # 从配置文件设置管道参数
                self.pdx_pipeline_params = self.pdx_config.get("PipelineParams", {
                    "use_doc_orientation_classify": False,
                    "use_doc_unwarping": False
                })
                logger.info("✅ PaddleX管道参数配置完成")
                
                # 设置印章检测参数
                self.seal_detection_params = self.pdx_config.get("SealDetection", {
                    "min_seal_size": 0.05,
                    "max_seal_size": 0.5,
                    "min_aspect_ratio": 0.5,
                    "max_aspect_ratio": 2.0,
                    "min_confidence": 0.2
                })
                logger.info("✅ PaddleX印章检测参数配置完成")
            except Exception as e:
                logger.warning(f"PaddleX管道创建失败：{str(e)}")
                self.pdx_pipeline = None
                self.pdx_pipeline_params = None
                self.seal_detection_params = None
            
            # 2. 独立加载手写体检测模型（关键修改）
            self.use_handwritten = use_handwritten
            self.handwritten_det_model = None
            self.handwritten_rec_model = None
            if use_handwritten:
                try:
                    # 初始化模型下载器
                    model_downloader = PaddleXModelFromHF()
                    
                    # 下载并加载版面检测模型
                    layout_model_dir = model_downloader.download_model(
                        repo_id=self.pdx_config["HuggingFace"]["LayoutDetection"]["repo_id"],
                        model_subdir=self.pdx_config["HuggingFace"]["LayoutDetection"].get("model_subdir"),
                        force_download=False
                    )
                    
                    if layout_model_dir and os.path.exists(layout_model_dir):
                        # 检查模型文件是否完整
                        required_files = ['model.pdparams', 'model.pdopt', 'config.yml', 'inference.yml']
                        missing_files = [f for f in required_files if not os.path.exists(os.path.join(layout_model_dir, f))]
                        
                        if not missing_files:
                            logger.info("版面检测模型文件完整，但PaddleX加载可能有问题，跳过独立模型加载")
                            # 不加载独立模型，使用管道中的模型
                            self.handwritten_det_model = None
                        else:
                            logger.warning(f"版面检测模型文件缺失：{missing_files}")
                            self.handwritten_det_model = None
                    else:
                        logger.warning("版面检测模型下载失败，手写体检测功能将不可用")
                        self.handwritten_det_model = None
                    
                    # 下载并加载识别模型
                    rec_model_dir = model_downloader.download_model(
                        repo_id=self.pdx_config["HuggingFace"]["Recognition"]["repo_id"],
                        model_subdir=self.pdx_config["HuggingFace"]["Recognition"].get("model_subdir"),
                        force_download=False
                    )
                    
                    if rec_model_dir and os.path.exists(rec_model_dir):
                        # 检查模型文件是否完整
                        required_files = ['model.pdparams', 'model.pdopt', 'config.yml', 'inference.yml']
                        missing_files = [f for f in required_files if not os.path.exists(os.path.join(rec_model_dir, f))]
                        
                        if not missing_files:
                            logger.info("识别模型文件完整，但PaddleX加载可能有问题，跳过独立模型加载")
                            # 不加载独立模型，使用管道中的模型
                            self.handwritten_rec_model = None
                        else:
                            logger.warning(f"识别模型文件缺失：{missing_files}")
                            self.handwritten_rec_model = None
                    else:
                        logger.warning("识别模型下载失败，手写体识别功能将不可用")
                        self.handwritten_rec_model = None
                    
                    # 由于PaddleX模型加载有问题，暂时禁用独立模型
                    logger.info("手写体功能将使用PaddleX管道中的模型，独立模型加载已跳过")
                        
                except Exception as e:
                    logger.warning(f"手写体模型初始化失败：{str(e)}")
                    self.handwritten_det_model = None
                    self.handwritten_rec_model = None
            
            # 加载手写体参数
            self.handwritten_detection_params = self.pdx_config.get("HandwrittenTextDetection", {
                "det_thresh": 0.3,
                "det_db_box_thresh": 0.3,
                "det_db_unclip_ratio": 1.8
            })
            
            # 加载手写体识别参数
            self.handwritten_recognition_params = self.pdx_config.get("HandwrittenTextRecognition", {
                "rec_thresh": 0.3,
                "rec_batch_num": 1,
                "max_text_length": 30
            })
        except ImportError:
            logger.warning("PaddleX未安装，无法使用PaddleX功能")
            self.pdx_pipeline = None
            self.use_handwritten = False
        except Exception as e:
            logger.warning(f"PaddleX初始化失败：{str(e)}")
            self.pdx_pipeline = None
            self.use_handwritten = False

    def detect_seal_region(self, img_path):
        """
        印章区域检测：使用PaddleX方法检测印章
        返回：(图章区域列表, 原图, 红色掩码图)
        """
        # 1. 读取图片并校验
        img = cv2.imread(img_path)
        if img is None:
            error_msg = f"无法读取图片：路径错误或文件损坏（路径：{img_path}）"
            logger.error(error_msg)
            raise ValueError(error_msg)
        logger.info(f"成功读取图片，尺寸：{img.shape[0]}x{img.shape[1]}")

        # 2. PaddleX方法检测
        paddlex_regions = []
        if self.pdx_pipeline is not None:
            paddlex_regions = self._detect_seal_paddlex(img, img_path)
        
        logger.info(f"PaddleX检测到印章区域总数：{len(paddlex_regions)}")
        
        return paddlex_regions, img, None

    def _detect_seal_paddlex(self, img, img_path):
        """PaddleX方法检测印章，返回所有检测到的区域"""
        try:
            logger.info("使用PaddleX扫描整个图片识别印章区域...")
            
            # 使用PaddleX印章识别管道扫描整个图片
            result_iter = self.pdx_pipeline.predict(
                img,
                **self.pdx_pipeline_params
            )
            result_list = list(result_iter)
            logger.info("PaddleX detect yield count: %d", len(result_list))
            result = result_list[-1] if result_list else {}
            seal_regions = []
            for predict_result in result_list:
                # 假设 predict_result 是你的检测结果（如日志中的印章1完整数据）
                logger.info(f"_extract_coordinates %s", predict_result)
                coordinates_list = self._extract_coordinates(predict_result)
                
                # 处理返回的坐标列表
                for coordinates in coordinates_list:
                    if coordinates:  # 确保坐标不为空
                        seal_regions.append((coordinates['x'], coordinates['y'], coordinates['w'], coordinates['h']))
                        logger.info(f"PaddleX印章：位置({coordinates['x']}, {coordinates['y']}), 尺寸({coordinates['w']}x{coordinates['h']}), 置信度{coordinates['score']:.3f}")
            # 返回所有检测到的区域
            if seal_regions:
                # 在原图标注所有图章区域（红框）
                img_marked = img.copy()
                for i, (x, y, w, h) in enumerate(seal_regions):
                    # 绘制红色边界框
                    cv2.rectangle(img_marked, (x, y), (x + w, y + h), (0, 0, 255), 2)  # 红色框
                    # 添加标签，显示PaddleX和置信度
                    label = f"PaddleX-{i+1}"
                    cv2.putText(img_marked, label, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
                marked_path = os.path.join(os.path.dirname(img_path), "seal_roi_marked.jpg")
                cv2.imwrite(marked_path, img_marked)
                logger.info(f"PaddleX已标注图章区域：{marked_path}（共{len(seal_regions)}个区域，前三个高置信度）")
                return seal_regions
            
            logger.info("PaddleX未检测到印章区域")
            return []
            
        except Exception as e:
            logger.warning(f"PaddleX检测失败：{str(e)}")
            return []

    def _extract_coordinates(self, predict_result):
        """提取PaddleX检测结果中的印章坐标（只选择label为'seal'的区域）"""
        logger.info("_extract_coordinates")
        
        # 从结果中获取布局检测的boxes列表
        boxes = predict_result.get('layout_det_res', {}).get('boxes', [])
        
        if not boxes:
            logger.info("没有检测到任何目标")
            return []  # 返回空列表
        
        logger.info("_extract_coordinates boxes: %d", len(boxes))
        # 过滤出真正的印章区域（label为'seal'）
        seal_boxes = [box for box in boxes if box.get('label') == 'seal']
        
        if not seal_boxes:
            logger.warning("没有检测到印章区域（label='seal'）")
            # 如果没有印章区域，记录所有检测到的区域类型
            labels = [box.get('label', 'unknown') for box in boxes]
            logger.info(f"检测到的区域类型: {set(labels)}")
            return []
        
        # 按置信度降序排序，取前三个印章
        sorted_seal_boxes = sorted(seal_boxes, key=lambda x: x['score'], reverse=True)
        top_seal_boxes = sorted_seal_boxes[:3]  # 取前三个印章
        
        logger.info(f"检测到{len(seal_boxes)}个印章区域，选择前{len(top_seal_boxes)}个高置信度印章")
        
        coordinates_list = []
        for i, box in enumerate(top_seal_boxes):
            # 提取坐标 [x1, y1, x2, y2]
            x1, y1, x2, y2 = box['coordinate']
            score = box['score']
            label = box.get('label', 'unknown')
            
            # 计算宽度和高度
            width = x2 - x1
            height = y2 - y1
            
            coordinate = {
                'x': int(x1),         # 左上角x坐标
                'y': int(y1),         # 左上角y坐标
                'w': int(width),      # 宽度
                'h': int(height),     # 高度
                'score': score,       # 置信度
                'label': label        # 标签
            }
            coordinates_list.append(coordinate)
            
            logger.info(f"印章{i+1}: 位置({x1},{y1}), 尺寸({width}x{height}), 置信度{score:.3f}, 标签{label}")
        
        return coordinates_list

    def recognize_seal_text(self, img_path, img, seal_regions):
        """
        识别多个印章区域的文字，使用PaddleX方法
        返回：识别结果列表
        """
        if not seal_regions:
            logger.warning("未检测到图章区域，无法识别文字")
            return []
        logger.info(f"开始识别{len(seal_regions)}个图章区域的文字")
        
        paddlex_results = []
        
        # PaddleX方法识别（如果启用）
        if self.pdx_pipeline is not None:
            # 为每个检测到的区域单独进行识别
            for i, seal_region in enumerate(seal_regions):
                try:
                    # 提取区域图像
                    x, y, w, h = seal_region
                    roi_img = img[y:y+h, x:x+w]
                    
                    if roi_img.size > 0:
                        # 对单个区域进行识别
                        region_text = self._recognize_single_region(roi_img, i+1)
                        if region_text:
                            paddlex_results.append({
                                "region": seal_region,
                                "text": region_text,
                                "method": "PaddleX"
                            })
                            logger.info(f"区域{i+1}识别结果：{region_text}")
                        else:
                            logger.warning(f"区域{i+1}识别失败")
                    else:
                        logger.warning(f"区域{i+1}图像为空")
                except Exception as e:
                    logger.warning(f"区域{i+1}识别异常：{str(e)}")
                    continue

        return paddlex_results

    def _recognize_single_region(self, roi_img, region_id):
        """识别单个印章区域的文字"""
        try:
            logger.info(f"开始识别区域{region_id}，图像尺寸: {roi_img.shape}")
            
            # 保存印章区域图像用于调试
            debug_path = f"seal_region_{region_id}_debug.jpg"
            cv2.imwrite(debug_path, roi_img)
            logger.info(f"保存印章区域图像: {debug_path}")
            
            # 尝试多种识别方法
            text = ""
            
            # 方法1：使用PaddleX印章识别管道
            try:
                logger.info(f"方法1：使用PaddleX印章识别管道")
                result_iter = self.pdx_pipeline.predict(roi_img, **self.pdx_pipeline_params)
                result_list = list(result_iter)
                result = result_list[-1] if result_list else {}
                
                if isinstance(result, dict) and "seal_res_list" in result:
                    seal_res_list = result["seal_res_list"]
                    if seal_res_list and len(seal_res_list) > 0:
                        for seal_res in seal_res_list:
                            if "rec_texts" in seal_res and seal_res["rec_texts"]:
                                text = " ".join(seal_res["rec_texts"]).strip()
                                if text:
                                    logger.info(f"方法1成功识别: '{text}'")
                                    break
            except Exception as e:
                logger.warning(f"方法1失败: {str(e)}")
            
            # 方法2：如果方法1失败，尝试使用完整的PaddleX管道
            if not text:
                try:
                    logger.info(f"方法2：使用完整PaddleX管道")
                    # 调整识别参数，降低阈值以提高识别率
                    predict_params = self.pdx_pipeline_params.copy()
                    predict_params.update({
                        'det_thresh': 0.1,  # 进一步降低检测阈值
                        'det_db_thresh': 0.2,  # 进一步降低DB阈值
                        'det_db_box_thresh': 0.2,  # 进一步降低框阈值
                        'drop_score': 0.05,  # 进一步降低丢弃阈值
                        'rec_batch_num': 1,  # 减少批处理大小
                        'max_text_length': 100,  # 增加最大文本长度
                    })
                    
                    result_iter = self.pdx_pipeline.predict(roi_img, **predict_params)
                    result_list = list(result_iter)
                    result = result_list[-1] if result_list else {}
                    
                    if isinstance(result, dict):
                        # 尝试从不同字段提取文本
                        if "seal_res_list" in result:
                            seal_res_list = result["seal_res_list"]
                            for seal_res in seal_res_list:
                                if "rec_texts" in seal_res and seal_res["rec_texts"]:
                                    text = " ".join(seal_res["rec_texts"]).strip()
                                    if text:
                                        logger.info(f"方法2成功识别: '{text}'")
                                        break
                        
                        if not text and "text_recognition" in result:
                            rec_result = result["text_recognition"]
                            if isinstance(rec_result, list) and len(rec_result) > 0:
                                text = rec_result[0].get("text", "").strip()
                                if text:
                                    logger.info(f"方法2从text_recognition识别: '{text}'")
                except Exception as e:
                    logger.warning(f"方法2失败: {str(e)}")
            
            # 方法3：如果前两种方法都失败，尝试图像预处理后再识别
            if not text:
                try:
                    logger.info(f"方法3：图像预处理后识别")
                    # 图像预处理：增强对比度
                    gray = cv2.cvtColor(roi_img, cv2.COLOR_BGR2GRAY)
                    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
                    enhanced = clahe.apply(gray)
                    enhanced_bgr = cv2.cvtColor(enhanced, cv2.COLOR_GRAY2BGR)
                    
                    result_iter = self.pdx_pipeline.predict(enhanced_bgr, **self.pdx_pipeline_params)
                    result_list = list(result_iter)
                    result = result_list[-1] if result_list else {}
                    
                    if isinstance(result, dict) and "seal_res_list" in result:
                        seal_res_list = result["seal_res_list"]
                        for seal_res in seal_res_list:
                            if "rec_texts" in seal_res and seal_res["rec_texts"]:
                                text = " ".join(seal_res["rec_texts"]).strip()
                                if text:
                                    logger.info(f"方法3成功识别: '{text}'")
                                    break
                except Exception as e:
                    logger.warning(f"方法3失败: {str(e)}")
            
            # 方法4：使用PaddleOCR直接识别
            if not text:
                try:
                    logger.info(f"方法4：使用PaddleOCR直接识别")
                    from paddleocr import PaddleOCR
                    
                    # 创建PaddleOCR实例
                    ocr = PaddleOCR(use_angle_cls=True, lang='ch', show_log=False)
                    
                    # 直接识别印章区域
                    result = ocr.ocr(roi_img, cls=True)
                    
                    if result and result[0]:
                        texts = []
                        for line in result[0]:
                            if line and len(line) >= 2:
                                text_content = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                                confidence = line[1][1] if isinstance(line[1], (list, tuple)) and len(line[1]) > 1 else 0.0
                                if confidence > 0.3:  # 只保留置信度较高的结果
                                    texts.append(text_content.strip())
                        
                        if texts:
                            text = " ".join(texts).strip()
                            logger.info(f"方法4成功识别: '{text}'")
                            
                            # 检查识别结果质量，如果文字不完整，继续尝试方法5
                            if len(text) < 8 or '未识别' in text or '识别失败' in text or '有限' not in text or '公司' not in text:
                                logger.info(f"方法4识别结果不完整，继续尝试方法5")
                                text = ""  # 清空结果，让方法5继续
                except Exception as e:
                    logger.warning(f"方法4失败: {str(e)}")
            
            # 方法5：红色分割 + 角度校正 + PaddleOCR识别
            if not text:
                try:
                    logger.info(f"方法5：红色分割 + 角度校正 + PaddleOCR识别")
                    from paddleocr import PaddleOCR
                    
                    # 创建PaddleOCR实例
                    ocr = PaddleOCR(use_angle_cls=True, lang='ch', show_log=False)
                    
                    # 1. 红色分割：提取印章的红色部分
                    red_seal = self._extract_red_seal(roi_img, region_id)
                    if red_seal is not None:
                        # 2. 角度校正：尝试多个角度
                        corrected_images = self._correct_seal_rotation(red_seal, region_id)
                        
                        # 3. 对每个校正后的图像进行OCR识别
                        best_text = ""
                        best_confidence = 0.0
                        
                        for angle, corrected_img in corrected_images:
                            try:
                                result = ocr.ocr(corrected_img, cls=True)
                                if result and result[0]:
                                    texts = []
                                    confidences = []
                                    for line in result[0]:
                                        if line and len(line) >= 2:
                                            text_content = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                                            confidence = line[1][1] if isinstance(line[1], (list, tuple)) and len(line[1]) > 1 else 0.0
                                            if confidence > 0.2:  # 降低阈值，因为红色分割后可能识别率较低
                                                texts.append(text_content.strip())
                                                confidences.append(confidence)
                                    
                                    if texts:
                                        # 计算平均置信度
                                        avg_confidence = sum(confidences) / len(confidences)
                                        combined_text = " ".join(texts).strip()
                                        
                                        if avg_confidence > best_confidence:
                                            best_text = combined_text
                                            best_confidence = avg_confidence
                                            logger.info(f"角度{angle}°识别结果: '{combined_text}', 置信度: {avg_confidence:.3f}")
                            except Exception as angle_error:
                                logger.debug(f"角度{angle}°识别失败: {str(angle_error)}")
                                continue
                        
                        if best_text:
                            text = best_text
                            logger.info(f"方法5成功识别: '{text}' (最佳角度置信度: {best_confidence:.3f})")
                except Exception as e:
                    logger.warning(f"方法5失败: {str(e)}")
            
            # 如果所有方法都失败，返回默认文本
            if not text:
                text = "未识别到文字"
                logger.warning(f"所有识别方法都失败")
            
            logger.info(f"区域{region_id}最终识别结果: '{text}'")
            return text
            
        except Exception as e:
            logger.warning(f"区域{region_id}识别失败：{str(e)}")
            return "识别失败"

    def _extract_red_seal(self, roi_img, region_id):
        """提取印章的红色部分"""
        try:
            # 转换到HSV颜色空间
            hsv = cv2.cvtColor(roi_img, cv2.COLOR_BGR2HSV)
            
            # 定义红色HSV范围
            lower_red1 = np.array([0, 43, 46])
            upper_red1 = np.array([10, 255, 255])
            lower_red2 = np.array([156, 43, 46])
            upper_red2 = np.array([180, 255, 255])
            
            # 创建红色掩码
            mask_red1 = cv2.inRange(hsv, lower_red1, upper_red1)
            mask_red2 = cv2.inRange(hsv, lower_red2, upper_red2)
            red_mask = cv2.bitwise_or(mask_red1, mask_red2)
            
            # 形态学操作：去除噪点
            kernel = np.ones((3,3), np.uint8)
            red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_CLOSE, kernel)
            red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_OPEN, kernel)
            
            # 只保留红色区域
            red_seal = cv2.bitwise_and(roi_img, roi_img, mask=red_mask)
            
            # 保存红色印章图像用于调试
            red_seal_path = f"red_seal_region_{region_id}_debug.jpg"
            cv2.imwrite(red_seal_path, red_seal)
            logger.info(f"保存红色印章图像: {red_seal_path}")
            
            # 检查红色区域是否足够大
            red_pixels = np.sum(red_mask > 0)
            total_pixels = red_mask.shape[0] * red_mask.shape[1]
            red_ratio = red_pixels / total_pixels
            
            if red_ratio < 0.01:  # 如果红色区域太小，可能不是印章
                logger.warning(f"区域{region_id}红色区域太小，比例: {red_ratio:.3f}")
                return None
            
            logger.info(f"区域{region_id}红色区域比例: {red_ratio:.3f}")
            return red_seal
            
        except Exception as e:
            logger.warning(f"区域{region_id}红色分割失败: {str(e)}")
            return None

    def _correct_seal_rotation(self, red_seal, region_id):
        """尝试多个角度校正印章图像"""
        corrected_images = []
        
        try:
            # 尝试的角度范围：-30°到30°，步长5°
            angles = list(range(-90, 181, 90))
            
            for angle in angles:
                if angle == 0:
                    # 原始角度
                    corrected_images.append((angle, red_seal))
                else:
                    # 旋转图像
                    height, width = red_seal.shape[:2]
                    center = (width // 2, height // 2)
                    
                    # 计算旋转矩阵
                    rotation_matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
                    
                    # 计算旋转后的边界
                    cos_angle = abs(rotation_matrix[0, 0])
                    sin_angle = abs(rotation_matrix[0, 1])
                    new_width = int((height * sin_angle) + (width * cos_angle))
                    new_height = int((height * cos_angle) + (width * sin_angle))
                    
                    # 调整旋转矩阵的平移部分
                    rotation_matrix[0, 2] += (new_width / 2) - center[0]
                    rotation_matrix[1, 2] += (new_height / 2) - center[1]
                    
                    # 执行旋转
                    rotated = cv2.warpAffine(red_seal, rotation_matrix, (new_width, new_height), 
                                          borderValue=(255, 255, 255))
                    
                    corrected_images.append((angle, rotated))
            
            # 保存校正后的图像用于调试
            for angle, corrected_img in corrected_images:
                if angle != 0:  # 跳过原始角度
                    corrected_path = f"corrected_seal_region_{region_id}_angle_{angle}_debug.jpg"
                    cv2.imwrite(corrected_path, corrected_img)
                    logger.debug(f"保存角度{angle}°校正图像: {corrected_path}")
            
            logger.info(f"区域{region_id}生成了{len(corrected_images)}个角度校正图像")
            return corrected_images
            
        except Exception as e:
            logger.warning(f"区域{region_id}角度校正失败: {str(e)}")
            return [(0, red_seal)]  # 返回原始图像

    def _recognize_paddlex_method(self, img, img_path):
        """PaddleX方法识别印章文字"""
        try:
            # 使用PaddleX印章识别管道识别（传递完整图像）
            result_iter = self.pdx_pipeline.predict(
                img,
                **self.pdx_pipeline_params
            )
            result_list = list(result_iter)
            result = result_list[-1] if result_list else {}
            # 提取识别结果
            text = ""
            if isinstance(result, dict):
                # 从PaddleX印章识别管道结果中提取文本
                if "seal_res_list" in result:
                    seal_res_list = result["seal_res_list"]
                    logger.info(f"PaddleX seal_res_list 长度: %d", len(seal_res_list))

                    if isinstance(seal_res_list, list) and len(seal_res_list) > 0:
                        # 遍历印章结果，提取文本
                        texts = []
                        for seal_res in seal_res_list:
                            if isinstance(seal_res, dict):
                                # 尝试从不同字段提取文本
                                if "rec_texts" in seal_res:
                                    rec_texts = seal_res["rec_texts"]
                                    if isinstance(rec_texts, list):
                                        texts.extend([t.strip() for t in rec_texts if t.strip()])
                                elif "text" in seal_res:
                                    texts.append(seal_res["text"].strip())
                                elif "rec_res" in seal_res and isinstance(seal_res["rec_res"], dict):
                                    if "text" in seal_res["rec_res"]:
                                        texts.append(seal_res["rec_res"]["text"].strip())
                                elif "ocr_res" in seal_res and isinstance(seal_res["ocr_res"], dict):
                                    if "text" in seal_res["ocr_res"]:
                                        texts.append(seal_res["ocr_res"]["text"].strip())
                        text = " ".join([t for t in texts if t])

                # 如果印章结果中没有文本，尝试其他字段
                if not text:
                    if "text_recognition" in result:
                        rec_result = result["text_recognition"]
                        if isinstance(rec_result, list) and len(rec_result) > 0:
                            text = rec_result[0].get("text", "").strip()
                    elif "text_detection" in result:
                        det_result = result["text_detection"]
                        if isinstance(det_result, list) and len(det_result) > 0:
                            text = det_result[0].get("text", "").strip()

            # 后处理：修正常见识别错误
            if text:
                # 移除可能的数字串（如注册号）
                import re
                # 保留中文和常见标点，移除纯数字串
                text_parts = text.split()
                filtered_parts = []
                for part in text_parts:
                    # 如果部分包含中文，保留；如果是纯数字串，跳过
                    if re.search(r'[\u4e00-\u9fff]', part):
                        filtered_parts.append(part)
                    elif not re.match(r'^\d+$', part):
                        filtered_parts.append(part)
                text = " ".join(filtered_parts)
                logger.info(f"PaddleX识别结果：{text}")
                return text
            else:
                logger.warning(f"PaddleX未识别到文字")
                return ""
                
        except Exception as e:
            logger.warning(f"PaddleX识别失败：{str(e)}")
            return ""

    def _preprocess_handwritten_image(self, img):
        """手写体图像预处理，提高识别效果"""
        try:
            # 1. 转换为灰度图
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            
            # 2. 增强对比度
            clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
            enhanced = clahe.apply(gray)
            
            # 3. 去噪
            denoised = cv2.medianBlur(enhanced, 3)
            
            # 4. 二值化（自适应阈值）
            binary = cv2.adaptiveThreshold(
                denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2
            )
            
            # 5. 形态学操作，连接断裂的笔画
            kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
            morphed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
            
            # 6. 转换回BGR格式
            processed_img = cv2.cvtColor(morphed, cv2.COLOR_GRAY2BGR)
            
            logger.info("手写体图像预处理完成")
            return processed_img
            
        except Exception as e:
            logger.warning(f"手写体图像预处理失败：{str(e)}")
            return img

    def _create_handwritten_transforms(self):
        """创建针对手写体的预处理pipeline"""
        try:
            # 尝试导入PaddleX transforms
            try:
                from paddlex import transforms as T
                
                # 定义针对手写体的预处理 pipeline（参数调整核心）
                handwritten_transforms = T.Compose([
                    T.GrayScale(),  # 必加：将彩色图转为灰度图，减少背景色干扰
                    T.Binarize(thresh=127),  # 必加：二值化，突出手写体笔画（黑底白字/白底黑字）
                    T.RandomDistort(brightness_range=0.2, contrast_range=0.2),  # 模拟手写体亮度不均
                    T.RandomErasing(prob=0.3, area_range=(0.01, 0.05)),  # 模拟手写体笔画缺损（增强鲁棒性）
                    # 关键：适配手写体长短差异（short_size=32 是识别模型标准输入高度）
                    T.ResizeByShort(short_size=32, max_size=2000),  # max_size=2000 支持长手写文本
                    T.Normalize(mean=[0.5], std=[0.5]),  # 灰度图单通道归一化
                ])
                
                logger.info("手写体预处理pipeline创建成功")
                return handwritten_transforms
                
            except ImportError:
                logger.warning("PaddleX transforms不可用，使用OpenCV预处理")
                return None
            
        except Exception as e:
            logger.warning(f"手写体预处理pipeline创建失败：{str(e)}")
            return None

    def detect_handwritten_text(self, img_path, seal_regions=None):
        """检测手写体文字区域，排除与印章识别区域相同且内容一致的区域"""
        if not self.use_handwritten or not self.pdx_pipeline:
            logger.info("手写体识别未启用或PaddleX不可用")
            return []
        
        try:
            img = cv2.imread(img_path)
            logger.info("开始手写体检测...")
            
            # 使用PaddleX版面检测来识别手写体区域
            logger.info("使用PaddleX版面检测进行手写体检测...")
            result_iter = self.pdx_pipeline.predict(img, **self.pdx_pipeline_params)
            result_list = list(result_iter)
            result = result_list[-1] if result_list else {}
            
            handwritten_regions = []
            
            if isinstance(result, dict) and 'layout_det_res' in result:
                boxes = result['layout_det_res'].get('boxes', [])
                logger.info(f"版面检测结果：{len(boxes)}个区域")
                
                # 过滤出手写体相关的区域（排除标题和段落标题，只保留普通文本）
                handwritten_labels = ['text']  # 只保留普通文本，排除标题类
                handwritten_boxes = [box for box in boxes if box.get('label') in handwritten_labels]
                
                logger.info(f"找到 {len(handwritten_boxes)} 个可能的手写体区域")
                
                for i, box in enumerate(handwritten_boxes):
                    x1, y1, x2, y2 = box['coordinate']
                    score = box['score']
                    label = box.get('label', 'unknown')
                    
                    # 计算尺寸
                    w = int(x2 - x1)
                    h = int(y2 - y1)
                    x = int(x1)
                    y = int(y1)
                    
                    # 过滤太小或太大的区域
                    if w < 20 or h < 10 or w > 1000 or h > 200:
                        continue
                    
                    # 检查是否与印章区域重叠
                    is_overlap_with_seal = False
                    if seal_regions:
                        try:
                            for seal in seal_regions:
                                if isinstance(seal, (tuple, list)) and len(seal) >= 4:
                                    seal_x, seal_y, seal_w, seal_h = seal[0], seal[1], seal[2], seal[3]
                                elif isinstance(seal, dict):
                                    seal_x, seal_y, seal_w, seal_h = seal['x'], seal['y'], seal['w'], seal['h']
                                else:
                                    continue
                                
                                # 检查重叠
                                if not (x + w < seal_x or x > seal_x + seal_w or y + h < seal_y or y > seal_y + seal_h):
                                    is_overlap_with_seal = True
                                    break
                        except Exception as overlap_error:
                            logger.debug(f"检查重叠失败: {str(overlap_error)}")
                            is_overlap_with_seal = False
                    
                    # 如果不与印章重叠，可能是手写体
                    if not is_overlap_with_seal:
                        handwritten_regions.append({
                            'region_id': len(handwritten_regions) + 1,
                            'x': x,
                            'y': y,
                            'w': w,
                            'h': h,
                            'detection_confidence': score,
                            'text': f"手写体区域{len(handwritten_regions) + 1}",
                            'label': label
                        })
                        
                        logger.info(f"手写体区域{len(handwritten_regions)}: 位置({x},{y}), 尺寸({w}x{h}), 置信度{score:.3f}, 标签{label}")
                        
                        # 限制检测数量
                        if len(handwritten_regions) >= 3:
                            break
            
            # 如果没有通过版面检测找到手写体，使用OpenCV方法作为备选
            if not handwritten_regions:
                logger.info("版面检测未找到手写体，使用OpenCV方法...")
                handwritten_regions = self._detect_handwritten_opencv(img, seal_regions)
            
            logger.info(f"手写体检测完成，找到 {len(handwritten_regions)} 个手写体区域")
            return handwritten_regions[:3]
            
        except Exception as e:
            logger.warning(f"PaddleX手写体检测失败：{str(e)}")
            return []

    def _detect_handwritten_opencv(self, img, seal_regions=None):
        """使用OpenCV方法检测手写体区域（备选方案）"""
        try:
            handwritten_regions = []
            
            # 1. 图像预处理
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            clahe = cv2.createCLAHE(clipLimit=1.5, tileGridSize=(8,8))
            enhanced = clahe.apply(gray)
            
            # 2. 使用边缘检测找到文本区域
            edges = cv2.Canny(enhanced, 50, 150)
            
            # 3. 查找轮廓
            contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            
            # 4. 过滤和筛选可能的手写体区域
            for i, contour in enumerate(contours):
                # 计算轮廓的边界框
                x, y, w, h = cv2.boundingRect(contour)
                
                # 过滤太小或太大的区域
                if w < 40 or h < 20 or w > 800 or h > 200:
                    continue
                
                # 计算轮廓面积与边界框面积的比值（手写体通常不规则）
                area = cv2.contourArea(contour)
                rect_area = w * h
                if rect_area > 0:
                    area_ratio = area / rect_area
                    
                    # 手写体通常有不规则的形状
                    if 0.3 < area_ratio < 0.8:
                        # 检查是否与印章区域重叠
                        is_overlap_with_seal = False
                        if seal_regions:
                            try:
                                for seal in seal_regions:
                                    if isinstance(seal, (tuple, list)) and len(seal) >= 4:
                                        seal_x, seal_y, seal_w, seal_h = seal[0], seal[1], seal[2], seal[3]
                                    elif isinstance(seal, dict):
                                        seal_x, seal_y, seal_w, seal_h = seal['x'], seal['y'], seal['w'], seal['h']
                                    else:
                                        continue
                                    
                                    # 检查重叠
                                    if not (x + w < seal_x or x > seal_x + seal_w or y + h < seal_y or y > seal_y + seal_h):
                                        is_overlap_with_seal = True
                                        break
                            except Exception as overlap_error:
                                logger.debug(f"检查重叠失败: {str(overlap_error)}")
                                is_overlap_with_seal = False
                        
                        # 如果不与印章重叠，可能是手写体
                        if not is_overlap_with_seal:
                            # 提取区域图像进行进一步分析
                            roi = img[y:y+h, x:x+w]
                            if roi.size > 0:
                                # 简单的文本特征检测
                                gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
                                
                                # 计算边缘密度
                                roi_edges = cv2.Canny(gray_roi, 50, 150)
                                import numpy as np
                                edge_density = np.sum(roi_edges > 0) / roi_edges.size
                                
                                # 如果边缘密度适中，可能是手写体
                                if 0.05 < edge_density < 0.3:
                                    handwritten_regions.append({
                                        'region_id': len(handwritten_regions) + 1,
                                        'x': int(x),
                                        'y': int(y),
                                        'w': int(w),
                                        'h': int(h),
                                        'detection_confidence': area_ratio,
                                        'text': f"手写体区域{len(handwritten_regions) + 1}",
                                        'label': "handwritten"
                                    })
                                    
                                    # 限制检测数量
                                    if len(handwritten_regions) >= 3:
                                        break
            
            return handwritten_regions
            
        except Exception as e:
            logger.warning(f"OpenCV手写体检测失败：{str(e)}")
            return []

    def _is_handwritten_region(self, img, x1, y1, x2, y2, text, label):
        """判断区域是否为手写体"""
        try:
            # 1. 基于版面检测标签判断
            if label in ["text", "title"]:
                # 2. 基于文本特征判断
                if text and len(text.strip()) > 0:
                    # 检查文本长度（手写体通常较短）
                    if len(text.strip()) <= 20:
                        # 检查文本内容（手写体通常包含中文字符）
                        import re
                        chinese_chars = re.findall(r'[\u4e00-\u9fff]', text)
                        if len(chinese_chars) > 0:
                            # 3. 基于图像特征判断（简单版本）
                            img_crop = img[int(y1):int(y2), int(x1):int(x2)]
                            if img_crop.size > 0:
                                # 检查图像复杂度（手写体通常有更多细节）
                                gray_crop = cv2.cvtColor(img_crop, cv2.COLOR_BGR2GRAY)
                                edges = cv2.Canny(gray_crop, 50, 150)
                                import numpy as np
                                edge_ratio = np.sum(edges > 0) / edges.size
                                
                                # 如果边缘比例适中，可能是手写体
                                if 0.05 < edge_ratio < 0.3:
                                    return True
            return False
        except Exception as e:
            logger.debug(f"手写体判断失败：{str(e)}")
            return False

    def _post_process_handwritten_text(self, text):
        """手写体文字后处理，提高识别准确性"""
        if not text:
            return text
        
        try:
            import re
            
            # 1. 移除多余空格
            text = re.sub(r'\s+', ' ', text.strip())
            
            # 2. 修正常见手写体识别错误
            corrections = {
                '0': 'O',  # 数字0误识别为字母O
                '1': 'I',  # 数字1误识别为字母I
                '5': 'S',  # 数字5误识别为字母S
                '8': 'B',  # 数字8误识别为字母B
            }
            
            for wrong, correct in corrections.items():
                text = text.replace(wrong, correct)
            
            # 3. 移除明显的噪声字符
            text = re.sub(r'[^\u4e00-\u9fff\w\s]', '', text)
            
            # 4. 长度过滤（手写体通常较短）
            if len(text) > 20:
                # 如果文本过长，可能是误识别，取前20个字符
                text = text[:20]
            
            return text
            
        except Exception as e:
            logger.warning(f"手写体文字后处理失败：{str(e)}")
            return text

    def recognize_handwritten_text(self, img, handwritten_regions):
        """识别手写体文字"""
        if not self.use_handwritten or not self.pdx_pipeline:
            return handwritten_regions
            
        try:
            logger.info("使用PaddleX识别手写体文字...")
            
            # 创建手写体预处理pipeline
            handwritten_transforms = self._create_handwritten_transforms()
            if handwritten_transforms is None:
                logger.warning("手写体预处理pipeline创建失败，使用默认预处理")
                processed_img = self._preprocess_handwritten_image(img)
            else:
                # 使用PaddleX预处理pipeline
                try:
                    processed_img = handwritten_transforms(img)
                    logger.info("使用PaddleX手写体预处理pipeline进行识别")
                except Exception as e:
                    logger.warning(f"PaddleX预处理失败，使用OpenCV预处理：{str(e)}")
                    processed_img = self._preprocess_handwritten_image(img)
            
            # 使用PaddleX识别手写体
            result_iter = self.pdx_pipeline.predict(
                processed_img,
                **self.handwritten_recognition_params
            )
            result_list = list(result_iter)
            result = result_list[-1] if result_list else {}
            
            # 提取手写体识别结果
            if isinstance(result, dict) and "seal_res_list" in result:
                seal_res_list = result["seal_res_list"]
                
                for i, seal_res in enumerate(seal_res_list):
                    if i < len(handwritten_regions):
                        # 提取识别文字
                        if "rec_texts" in seal_res:
                            rec_texts = seal_res["rec_texts"]
                            if isinstance(rec_texts, list) and rec_texts:
                                raw_text = " ".join(rec_texts)
                                # 应用后处理
                                processed_text = self._post_process_handwritten_text(raw_text)
                                handwritten_regions[i]['text'] = processed_text
                        
                        # 提取识别置信度
                        if "rec_scores" in seal_res:
                            rec_scores = seal_res["rec_scores"]
                            if isinstance(rec_scores, list) and rec_scores:
                                handwritten_regions[i]['recognition_confidence'] = max(rec_scores)
            
            return handwritten_regions
            
        except Exception as e:
            logger.warning(f"PaddleX手写体识别失败：{str(e)}")
            return handwritten_regions

    def _filter_handwritten_regions(self, handwritten_regions, seal_regions):
        """过滤手写体区域，排除与印章识别区域相同且内容一致的区域"""
        try:
            filtered_regions = []
            
            for handwritten_region in handwritten_regions:
                hx, hy, hw, hh = handwritten_region['x'], handwritten_region['y'], handwritten_region['w'], handwritten_region['h']
                should_keep = True
                
                # 检查是否与印章区域重叠
                for seal_region in seal_regions:
                    if isinstance(seal_region, tuple) and len(seal_region) == 4:
                        sx, sy, sw, sh = seal_region
                    elif isinstance(seal_region, dict):
                        sx, sy, sw, sh = seal_region.get('x', 0), seal_region.get('y', 0), seal_region.get('w', 0), seal_region.get('h', 0)
                    else:
                        continue
                    
                    # 计算重叠度
                    overlap_ratio = self._calculate_overlap_ratio(
                        (hx, hy, hw, hh), (sx, sy, sw, sh)
                    )
                    
                    # 如果重叠度超过阈值，认为是相同区域
                    if overlap_ratio > 0.5:  # 50%重叠阈值
                        logger.info(f"手写体区域({hx},{hy},{hw},{hh})与印章区域({sx},{sy},{sw},{sh})重叠度{overlap_ratio:.3f}，需要进一步检查内容")
                        
                        # 这里可以添加内容对比逻辑
                        # 由于印章识别内容可能还没有，暂时保留该区域
                        # 在实际应用中，可以对比识别出的文字内容
                        should_keep = True  # 暂时保留，后续可以优化
                        break
                
                if should_keep:
                    filtered_regions.append(handwritten_region)
                    logger.info(f"保留手写体区域: 位置({hx},{hy}), 尺寸({hw}x{hh})")
                else:
                    logger.info(f"过滤手写体区域: 位置({hx},{hy}), 尺寸({hw}x{hh})")
            
            return filtered_regions
            
        except Exception as e:
            logger.warning(f"手写体区域过滤失败：{str(e)}")
            return handwritten_regions

    def _calculate_overlap_ratio(self, region1, region2):
        """计算两个区域的重叠度"""
        try:
            x1, y1, w1, h1 = region1
            x2, y2, w2, h2 = region2
            
            # 计算交集
            x_left = max(x1, x2)
            y_top = max(y1, y2)
            x_right = min(x1 + w1, x2 + w2)
            y_bottom = min(y1 + h1, y2 + h2)
            
            if x_right <= x_left or y_bottom <= y_top:
                return 0.0  # 没有交集
            
            intersection_area = (x_right - x_left) * (y_bottom - y_top)
            area1 = w1 * h1
            area2 = w2 * h2
            
            # 计算重叠度（相对于较小区域的面积）
            min_area = min(area1, area2)
            overlap_ratio = intersection_area / min_area if min_area > 0 else 0.0
            
            return overlap_ratio
            
        except Exception as e:
            logger.warning(f"计算重叠度失败：{str(e)}")
            return 0.0

    def visualize_handwritten_regions(self, img, handwritten_regions, img_path):
        """可视化手写体区域，合并到seal_roi_marked.jpg中"""
        try:
            # 尝试读取现有的seal_roi_marked.jpg，如果不存在则使用原图
            marked_path = os.path.join(os.path.dirname(img_path), "seal_roi_marked.jpg")
            if os.path.exists(marked_path):
                img_marked = cv2.imread(marked_path)
                logger.info("读取现有的seal_roi_marked.jpg，添加手写体标注")
            else:
                img_marked = img.copy()
                logger.info("创建新的标注图像，添加手写体标注")
            
            # 定义颜色（绿色用于手写体）
            color = (0, 255, 0)  # 绿色
            
            for i, region in enumerate(handwritten_regions):
                x, y, w, h = region['x'], region['y'], region['w'], region['h']
                detection_conf = region['detection_confidence']
                recognition_conf = region.get('recognition_confidence', 0.0)
                text = region.get('text', '')
                
                # 绘制矩形框
                cv2.rectangle(img_marked, (x, y), (x + w, y + h), color, 2)
                
                # 添加标签
                label = f"handwriting{i+1}: {text[:10]}..." if len(text) > 10 else f"handwriting{i+1}: {text}"
                cv2.putText(img_marked, label, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)
                
                # 添加置信度信息
                conf_label = f" {detection_conf:.3f} {recognition_conf:.3f}"
                cv2.putText(img_marked, conf_label, (x, y+h+20), cv2.FONT_HERSHEY_SIMPLEX, 0.4, color, 1)
            
            # 保存合并后的标注图像（覆盖seal_roi_marked.jpg）
            cv2.imwrite(marked_path, img_marked)
            logger.info(f"手写体区域已合并到：{marked_path}")
            
            return marked_path
            
        except Exception as e:
            logger.warning(f"手写体可视化失败：{str(e)}")
            return None


if __name__ == "__main__":
    import sys
    
    # 配置日志级别
    logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(name)s:%(message)s')
    
    if len(sys.argv) < 2:
        print("使用方法: python PaddleXSealDetector.py <图片路径> [--handwritten]")
        print("")
        print("示例:")
        print("  python PaddleXSealDetector.py image.jpg")
        print("  python PaddleXSealDetector.py image.jpg --handwritten")
        print("")
        print("功能说明:")
        print("  - 使用PaddleX检测印章区域")
        print("  - 使用PaddleX识别印章文字")
        print("  - 支持手写体检测和识别（可选）")
        print("  - 生成调试图像：seal_roi_marked.jpg")
        print("")
        print("注意：首次运行会自动下载Hugging Face模型")
        sys.exit(1)
    
    img_path = sys.argv[1]
    use_handwritten = "--handwritten" in sys.argv
    
    print("=" * 60)
    print("PaddleXSealDetector 印章识别演示")
    print("=" * 60)
    print(f"图片路径: {img_path}")
    print("使用技术: PaddleX + Hugging Face模型")
    if use_handwritten:
        print("手写体识别: 已启用")
    print("=" * 60)
    
    try:
        # 创建检测器
        detector = PaddleXSealDetector(use_handwritten=use_handwritten)
        
        if detector.pdx_pipeline is None:
            print("❌ PaddleX初始化失败，请检查PaddleX安装")
            sys.exit(1)
        
        # 1. 检测印章区域
        print("\n1. 检测印章区域...")
        seal_regions, img, red_mask = detector.detect_seal_region(img_path)
        
        if seal_regions:
            print(f"✅ 检测到 {len(seal_regions)} 个印章区域")
            for i, (x, y, w, h) in enumerate(seal_regions):
                print(f"   区域{i+1}: 位置({x},{y}), 尺寸({w}x{h})")
        else:
            print("❌ 未检测到印章区域")
        
        # 2. 识别印章文字
        print("\n2. 识别印章文字...")
        if seal_regions:
            recognition_results = detector.recognize_seal_text(img_path, img, seal_regions)
            
            if recognition_results:
                print("✅ 印章文字识别结果:")
                for i, result in enumerate(recognition_results):
                    region = result["region"]
                    text = result["text"]
                    method = result["method"]
                    if text == "未识别到文字" or text == "" :
                        continue
                    x, y, w, h = region
                    print(f"   区域{i+1} ({method}): {text}")
                    print(f"     位置: ({x},{y}), 尺寸: ({w}x{h})")
            else:
                print("❌ 未识别到印章文字")
        
        # 3. 手写体检测和识别（如果启用）
        if use_handwritten:
            print("\n3. 手写体检测和识别...")
            handwritten_regions = detector.detect_handwritten_text(img_path, seal_regions)
            
            if handwritten_regions:
                print(f"✅ 检测到 {len(handwritten_regions)} 个手写体区域")
                
                # 识别手写体文字
                handwritten_regions = detector.recognize_handwritten_text(img, handwritten_regions)
                
                # 可视化手写体区域
                detector.visualize_handwritten_regions(img, handwritten_regions, img_path)
                
                print("✅ 手写体识别结果:")
                for region in handwritten_regions:
                    x, y, w, h = region['x'], region['y'], region['w'], region['h']
                    text = region.get('text', '')
                    detection_conf = region['detection_confidence']
                    recognition_conf = region.get('recognition_confidence', 0.0)
                    print(f"   区域{region['region_id']}: {text}")
                    print(f"     位置: ({x},{y}), 尺寸: ({w}x{h})")
                    print(f"     检测置信度: {detection_conf:.3f}, 识别置信度: {recognition_conf:.3f}")
            else:
                print("❌ 未检测到手写体区域")
        
        # 4. 生成的文件
        print("\n4. 生成的调试文件:")
        debug_files = ["seal_roi_marked.jpg"]
        
        for file in debug_files:
            file_path = os.path.join(os.path.dirname(img_path), file)
            if os.path.exists(file_path):
                print(f"   ✅ {file}")
            else:
                print(f"   ❌ {file} (未生成)")
        
        print("\n" + "=" * 60)
        print("识别完成！")
        print("=" * 60)
        
    except Exception as e:
        print(f"\n❌ 识别过程出错: {str(e)}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
